package com.bjpowernode.boss.mvc.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bjpowernode.boss.common.client.RedisClient;
import com.bjpowernode.boss.common.constant.KeyConst;
import com.bjpowernode.boss.common.enums.ResponseCode;
import com.bjpowernode.boss.common.exception.BossException;
import com.bjpowernode.boss.common.utils.JwtUtil;
import com.bjpowernode.boss.dao.entity.PmsMenu;
import com.bjpowernode.boss.dao.entity.PmsOperator;
import com.bjpowernode.boss.dao.mapper.PmsMenuMapper;
import com.bjpowernode.boss.dao.mapper.PmsOperatorMapper;
import com.bjpowernode.boss.mvc.models.dto.operator.LoginResponseDto;
import com.bjpowernode.boss.mvc.models.form.operator.LoginForm;
import com.bjpowernode.boss.mvc.models.menus.MenuItem;
import com.bjpowernode.boss.mvc.models.menus.SubMenu;
import com.bjpowernode.boss.mvc.service.OperatorService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author yu
 * @date 2024/7/7  10:29
 */

@Service
public class OperatorServiceImpl implements OperatorService {

    @Resource
    private RedisClient redisClient ;

    @Resource
    private PmsOperatorMapper pmsOperatorMapper ;

    @Resource
    private PmsMenuMapper pmsMenuMapper ;

    @Override
    public LoginResponseDto operatorLogin(LoginForm loginForm) {
        // pms_operator表 login_name字段值是唯一的
        QueryWrapper<PmsOperator> wrapper = new QueryWrapper<>() ;
        wrapper.eq("login_name", loginForm.getLoginName()) ;
        PmsOperator operator = pmsOperatorMapper.selectOne(wrapper) ;

        // 如果用户不存在
        if (operator == null) {
            throw new BossException(ResponseCode.OPERATOR_LOGIN_NAME_PWD_ERROR) ; // 登录名或密码错误（模糊提示）
        }

        // 到这里，说明用户存在。则将前端登录页面传来的密码进行加盐加密后，再与数据库中记录的密码（这个是加密过的）进行比对
        String paramLoginPwd = DigestUtil.md5Hex(loginForm.getLoginPwd() + operator.getSalt()) ;
        if (!operator.getLoginPwd().equals(paramLoginPwd)) {
            throw new BossException(ResponseCode.OPERATOR_LOGIN_NAME_PWD_ERROR_1) ;
        }

        // 生成jwt
        String jwt = JwtUtil.generateToken(UUID.randomUUID().toString(), 120) ;

        // 将jwt写入Redis数据库

        // 要写入Redis的数据
        HashMap<String, String> redisData = new HashMap<>() ;
        // 操作员的id
        redisData.put("operatorId", String.valueOf(operator.getId())) ;
        // 展示名
        redisData.put("showName", operator.getShowName()) ;
        // jwt
        redisData.put("jwt", jwt) ;
        // 登录时间
        redisData.put("loginTime", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:SS")) ;

        String redisKey = KeyConst.TOKEN_OPERATOR + operator.getId() ;

        Boolean saveToken = redisClient.setHashMap(redisKey, redisData, 120, TimeUnit.MINUTES) ;

        if (!saveToken) {
            throw new BossException(ResponseCode.OPERATOR_SAVE_TOKEN_ERROR) ;
        }

        // 登录成功，保存jwt成功。返回登录结果给前端
        return new LoginResponseDto(operator.getId(), operator.getShowName(), jwt) ;
    }

    /**
     * 根据登录的操作员获取菜单列表
     *
     * @param operatorId
     * @return
     */
    @Override
    public List<SubMenu> getMenusByLoginOperator(Long operatorId) {
        // 从数据库查询菜单数据
        List<PmsMenu> pmsMenuList = pmsMenuMapper.selectListByOperatorId(operatorId) ;

        // Map<string, list<PmsMenu>    key是Number列的前4位， Value是 与Number前四位相同的list
        String numberPrefix4 = "" ;
        Map<String, List<PmsMenu>> listMapMenu = new HashMap<>() ;
        for (PmsMenu pmsMenu : pmsMenuList) {
            numberPrefix4 = pmsMenu.getNumber().substring(0, 4) ;

            if (listMapMenu.containsKey(numberPrefix4)) {
                listMapMenu.get(numberPrefix4).add(pmsMenu) ;
            }
            else {
                List<PmsMenu> list = new ArrayList<>() ;
                list.add(pmsMenu) ;
                listMapMenu.put(numberPrefix4, list) ;
            }
        }

        // 从map中查询菜单，对list进行组装，得到list<SubMenu>
        List<SubMenu> subMenuList = new ArrayList<>() ;
        listMapMenu.forEach((number, menuList) -> {
            String isLeaf = "" ;
            SubMenu subMenu = new SubMenu() ;
            List<MenuItem> items = new ArrayList<>() ;

            for (PmsMenu pmsMenu : menuList) {
                isLeaf = pmsMenu.getIsLeaf() ;
                if ("NO".equals(isLeaf)) {
                    subMenu.setName(pmsMenu.getName());
                    subMenu.setUrl(pmsMenu.getUrl());
                    subMenu.setNumber(pmsMenu.getNumber());
                }
                else {
                    MenuItem item = new MenuItem() ;
                    item.setName(pmsMenu.getName());
                    item.setUrl(pmsMenu.getUrl());
                    item.setNumber(pmsMenu.getNumber());

                    items.add(item) ;
                }
            }

            // 为subMenu的items赋值
            subMenu.setItems(items);
            // 添加到subMenuList
            subMenuList.add(subMenu) ;
        });

        return subMenuList.stream().sorted(Comparator.comparing(SubMenu::getNumber)).toList() ;
    }
}
